package com.ruoyi.data;

import com.ruoyi.common.exception.UtilException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.SortedMap;
import java.util.TimeZone;

public class SignUtil {
  private static final Charset UTF8 = StandardCharsets.UTF_8;
  private static final String SECURITY_KEY = "QKV1";
  private static final String SERVICE = "OPEN";
  private static final String MAC = "qk1_request";

  private SignUtil() {
    super();
  }

  public static String sign(SortedMap reqParams, String tenantSecret) {
    String stringToSign = spellSignString(reqParams, tenantSecret);
    String timestamp = reqParams.get("timestamp").toString();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    // 注意时区，否则容易出错
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
    String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
    byte[] secretDate = hmac256((SECURITY_KEY + tenantSecret).getBytes(UTF8), date);
    byte[] secretService = hmac256(secretDate, SERVICE);
    byte[] secretSigning = hmac256(secretService, MAC);
    String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, sha256Hex(stringToSign))).toUpperCase();
    return signature.toUpperCase();
  }

  private static byte[] hmac256(byte[] key, String msg) {
    Mac mac = null;
    try {
      mac = Mac.getInstance("HmacSHA256");
    } catch (NoSuchAlgorithmException e) {
      throw new UtilException("hmac256失败", e);
    }
    SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
    try {
      mac.init(secretKeySpec);
    } catch (InvalidKeyException e) {
      throw new UtilException("无效的Key", e);
    }
    return mac.doFinal(msg.getBytes(UTF8));
  }

  private static String sha256Hex(String s) {
    MessageDigest md = null;
    try {
      md = MessageDigest.getInstance("SHA-256");
    } catch (NoSuchAlgorithmException e) {
      throw new UtilException("没有SHA-256签名算法", e);

    }
    byte[] d = md.digest(s.getBytes(UTF8));
    return DatatypeConverter.printHexBinary(d).toLowerCase();
  }

  private static String spellSignString(SortedMap<String,String> values, String secretKey) {
    StringBuilder sb = new StringBuilder();
    for (Map.Entry<String,String> s : values.entrySet()) {
      String key = s.getKey();
      Object value = s.getValue();
      if (value == null || "".equals(value.toString()) || "sign".equals(key)) {
        continue;
      }
      sb.append(key).append("=").append(value).append("&");
    }
    //拼接租户秘钥
    sb.append("tenant_secret").append("=").append(secretKey);
    return sb.toString();
  }
}